﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace colas
{
    class EventoFinEntregaPedido : IEvento
    {
        private int empleado;
        private double tConsumicionPedido;
        private double tAdicionalesConsumicion;
        private double tEntregaPedido;
        private double tiempo_espera_paquete_chico;
        private double tiempo_espera_paquete_grande;
        private gridline linea_actual;
        /*public EventoFinEntregaPedido(int valor)
        {
            this.empleado = valor;
        }
        */
        public EventoFinEntregaPedido(int valor, double tConsumicionPedido, double tAdicionalesConsumicion, double tEntregaPedido, double _tiempo_espera_paquete_chico, double _tiempo_espera_paquete_grande)
        {
            this.empleado = valor;
            this.tConsumicionPedido=tConsumicionPedido;
            this.tAdicionalesConsumicion = tAdicionalesConsumicion;
            this.tEntregaPedido=tEntregaPedido;
            this.tiempo_espera_paquete_chico = _tiempo_espera_paquete_chico;
            this.tiempo_espera_paquete_grande = _tiempo_espera_paquete_grande;
        }
        public gridline llenarLinea(gridline linea_anterior)
        {
            linea_actual = new gridline(linea_anterior);// instancion la grilla
            // y la lleno con el autocompletar de inicializar()
  
            if (this.empleado == 1) // el evento puede ser disparado
                // el empleado 1 o 2 controlo el parametro de entrada que
                // me indica eso
            {
                //evento instanciado por el primer empleado
                linea_actual.evento = (int)Utils.eventos.FIN_ENTREGA_1;
                linea_actual.Reloj = linea_anterior.fin_entrega1;
                linea_actual.fin_entrega1 = -1;
                // verifico si hay algo en cola de entrega
                verificar_en_espera_entrega(linea_anterior);
                verificar_cola_vacia(linea_anterior);
            }
            else
            {
                //evento instanciado por el primer empleado
                linea_actual.evento = (int)Utils.eventos.FIN_ENTREGA_2;
                linea_actual.Reloj = linea_anterior.fin_entrega2;
                linea_actual.fin_entrega2 = -1;
                // verifico si hay algo en cola de entrega
                verificar_en_espera_entrega(linea_anterior);
                verificar_cola_vacia(linea_anterior);
            }
            // llamo a hacer finalizacion y retorno
            return linea_actual;
        }
        public void verificar_cola_vacia(gridline linea_anterior)
        {
            // verifico si quedo algo en la cola de entrega
            if (linea_anterior.cola_entrega == 0) // si la cola de entrega es 0
            {
                cambiar_estado_empleado_i(false);
            }
            else
            {
                linea_actual.cola_entrega = linea_anterior.cola_entrega - 1;
                cambiar_estado_empleado_i(true);
                // falta verificacion 
                int index0 = verificar_cliente_primero_en_cola();
                if (index0 >= 0)
                {
                    gridline.clientes[index0].estado = (int)Utils.cliente.ESPERANDO_ENTREGA;
                    generarTiempoEntregaCliente();
                }         
            }
            

        }
        // primer cliente en cola entrega
        public int verificar_cliente_primero_en_cola()
         {
            int hay_cliente_entrega = -1; // si es -1 no habia nadie
            int i=0;
            foreach (Cliente cli in gridline.clientes)
            {
                i++;
                if (cli.estado == (int)Utils.cliente.EN_COLA_ENTREGA)
                {
                    hay_cliente_entrega = i-1; // ya que puedo devolver el 0 
                    break; 
                }
            }
            return hay_cliente_entrega; // retorno si hay. hay si es >= 0 sino es -1
        }
        
        public int verificar_clientes_espera_entrega()
        // verifica si al menos hay algun cliente con estado en cola de entrega
        // y retorna dicho valor
        {
            int hay_cliente_entrega = -1; // si es -1 no habia nadie
            int i=0;
            foreach (Cliente cli in gridline.clientes)
            {
                i++;
                if (cli.estado == (int)Utils.cliente.ESPERANDO_ENTREGA)
                {
                    hay_cliente_entrega = i-1; // ya que puedo devolver el 0 
                    break; 
                }
            }
            return hay_cliente_entrega; // retorno si hay. hay si es >= 0 sino es -1
        }
        // extras
        public void cambiar_estado_empleado_i(bool esOcupado) 
        {
            // Veo que empleado era el ultimo que estaba atendiendo
            if (this.empleado == 1)
            {
                // si era el primer empleado le cambio el estado a libre si esOcupado es false
                if(esOcupado==false) linea_actual.estado_empleado1 = (int)Utils.empleado.LIBRE;
                else linea_actual.estado_empleado1 = (int)Utils.empleado.OCUPADO;            
            }
            else
            {
                // si era el segundo empleado le cambio el estado a libre si esOcupado es true
                if (esOcupado == false) linea_actual.estado_empleado2 = (int)Utils.empleado.LIBRE;
                else linea_actual.estado_empleado2 = (int)Utils.empleado.OCUPADO; 
            }
        }
        // Metodos para generar numeros aleatorios
        
        public void generarTiempoConsumoCliente(Cliente cli) // dist random uniforme
        {
            double a = this.tConsumicionPedido-this.tAdicionalesConsumicion;
            double b = this.tAdicionalesConsumicion * 2;
            double rand = NumeroRandom.getInstance().NextDouble();
            cli.rndCliente = rand;            
            cli.finComsumicion = linea_actual.Reloj + a + b * rand;
        }
        // Modificar este metodo para generar 
        public void generarTiempoEntregaCliente() // dist exp neg
        {
            if (empleado == 1)
            {
                double rand= NumeroRandom.getInstance().NextDouble();
                linea_actual.rnd_entrega1= rand;
                linea_actual.fin_entrega1 = linea_actual.Reloj + (-1 * tEntregaPedido * (Math.Log(1 - rand)));
            }
            else
            {
                double rand= NumeroRandom.getInstance().NextDouble();
                linea_actual.rnd_entrega2= rand;
                linea_actual.fin_entrega2 = linea_actual.Reloj + (-1 * tEntregaPedido * (Math.Log(1 - rand)));
            }
        }

        public void verificar_en_espera_entrega(gridline linea_anterior)
        {
            // verifico que alla al menos un cliente en la cola de espera
            int index1 = verificar_clientes_espera_entrega();
            if (index1 >= 0) // si hay al menos un cliente en espera
            {
                Eleccion elect = new Eleccion(); // creo una election
                double rnd_consumir = NumeroRandom.getInstance().NextDouble();
                linea_actual.rnd_eleccion_consumir = rnd_consumir;
                linea_actual.eleccion_consumir = elect.getSegundaEleccion(rnd_consumir);
                if (linea_actual.eleccion_consumir == (int)Utils.eleccion_consumir.SI)
                {
                    // Si la eleccion a consumir es no, cambio el estado del cliente
                    // a consumiendo
                    gridline.clientes[index1].estado = (int)Utils.cliente.CONSUMIENDO;
                    //double rand = NumeroRandom.getInstance().NextDouble();
                    //gridline.clientes[index1].rndCliente = rand;
                    gridline.clientes[index1].rndCliente = rnd_consumir;
                   // linea_actual.eleccion_consumir = 0;
                    //gridline.clientes[index1].finComsumicion = elect.getSegundaEleccion(rand);

                    // Calculo el Tiempo de consumicion del cliente y lo aniado a la linea_actual.
                    double rnd_tamanio_pedido = NumeroRandom.getInstance().NextDouble();
                    gridline.clientes[index1].tamanio = elect.getTerceraEleccion(rnd_tamanio_pedido);
                    //TP6
                    gridline.clientes[index1].finComsumicion = linea_actual.Reloj + (gridline.clientes[index1].tamanio == (int)Utils.eleccion_tamanio.CHICO ? this.tiempo_espera_paquete_chico : this.tiempo_espera_paquete_grande);
                    //generarTiempoConsumoCliente(gridline.clientes[index1]);
                }
                else
                {
                    // Si la eleccion a consumir es no, cambio el estado del cliente
                    // a destuccion
                    gridline.clientes[index1].estado = (int)Utils.cliente.DESTRUCCION;
                    gridline.clientes[index1].horaSalida = linea_actual.Reloj;
                    linea_actual.contador_personas = linea_anterior.contador_personas + 1;
                   // linea_actual.eleccion_consumir = 1;
                }
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("No hay clientes en espera entrega");
            }
    }
  
   }
}
